﻿using System;
using System.Collections.Generic;
using System.Text;
using System.Threading;
using System.Collections;

namespace Exec
{
    // 쓰레드 풀
    public class Pool
    {
        private static Queue<IJob> ready =
            new Queue<IJob>();

        
        private static List<IJob> excute =
            new List<IJob>();

        private Queue<Worker> workers;

        public Pool(int capacity)
        {
            workers = new Queue<Worker>();

            Init(capacity);
        }

        private void Init(int capacity)
        {            
            for(;capacity > 0; capacity--)
            {
                workers.Enqueue(new Worker());
            }
        }

        private class Worker
        {
            private Thread th;
            private IJob job;
            private bool loop;

            public Worker()
            {
                th = new Thread(new ThreadStart(this.Run));
                loop = true;
                th.Start();
            }

            public void Run()
            {          
                while(loop)
                {
                    lock (ready)
                    {
                        //Console.WriteLine(">> 대기");
                        
                        if (loop)
                        {
                            Monitor.Wait(ready);
                        }

                        if (ready.Count == 0)
                        {
                            continue;
                        }

                        job = ready.Dequeue();

                        lock (excute)
                        {
                            excute.Add(job);
                        }
                    }

                    //Console.WriteLine(">> 업무 시작");
                    job.Task();

                    lock (excute)
                    {
                        excute.Remove(job);
                    }
                    //Console.WriteLine(">> 업무 끝");
                }

                //Console.WriteLine(">> 해고");
            }

            public void Out()
            {
                loop = false;
            }

            public void Terminate()
            {
            }
        }

        // 준비큐에 작업 추가
        public static void SetReady(IJob job)
        {
            lock (ready)
            {
                ready.Enqueue(job);
                //Console.WriteLine(">> 작업추가");
                Monitor.Pulse(ready);
            }
        }

        // 모두 종료
        public void Join()
        {
            //Console.WriteLine(">> 모두 해고");

            foreach (Worker wk in workers)
            {
                // 워커 루프를 탈출합니다..
                wk.Out();
            }

            ExcuteJoin();
        }

        private void ExcuteJoin()
        {
            lock (ready)
            {
                Monitor.PulseAll(ready);
            }

            lock (excute)
            {
                foreach (IJob job in excute)
                {
                    job.Stop();
                }
            }
        }

    }
}
